
#ifndef Texture_h
#define Texture_h

#include <Defines.h>
#include <CSharpPropertyMethods.h>

#include <System/Object.h>
#include <System/IDisposable.h>
#include <System/NotImplementedException.h>
#include <System/Math.h>

#include "GraphicsResource.h"
#include "SurfaceFormat.h"
#include "States/SamplerState.h"

// OpenGL. That is not implemented.
//#include "TextureTarget.h"
//#include "TextureUnit.h"
class TextureTarget;
class TextureUnit;

namespace Riccsson
{
	namespace Xna
	{
		namespace Framework
		{
			namespace Graphics
			{
				class Texture
					//: public Riccsson::System::Object // Already defined in GraphicsResource.
					//, public Riccsson::System::IDisposable // Already defined in GraphicsResource.
					: public GraphicsResource
				{
					friend class SpriteBatch;

					protected: SurfaceFormat format;
					protected: int levelCount;

			//#if DIRECTX
			//
			//		protected: SharpDX.Direct3D11.Resource _texture;
			//
			//		private SharpDX.Direct3D11.ShaderResourceView _resourceView;
			//
			//#elif OPENGL
					public: /*internal*/ int GlTexture; // = -1;
					//public: /*internal*/ GC_PTR<TextureTarget> glTarget; // TextureTarget = OpenGL.
					//public: /*internal*/ GC_PTR<TextureUnit> glTextureUnit; // = TextureUnit:::Texture0; // TextureUnit = OpenGL.
					//public: /*internal*/ GC_PTR<SamplerState> glLastSamplerState; // = null;
			//#endif

					public: Texture()
						: GlTexture(-1)
						//, glTarget( nullptr )
						//, glTextureUnit( nullptr ) // = TextureUnit.Texture0
						//, glLastSamplerState( null )
					{
									
					}
		
					public: PROP3_GET(SurfaceFormat, Format)
					{
						return format;
					}
					private: PROP3_SET(SurfaceFormat, Format){throw;}
		
					public: PROP3_GET(int, LevelCount)
					{
						return levelCount;
					}
					private: PROP3_SET(int, LevelCount){throw;}

					public: /*internal*/ static int CalculateMipLevels(int width, int height = 0, int depth = 0)
					{
						int levels = 1;
						int size = Riccsson::System::Math::Max(Riccsson::System::Math::Max(width, height), depth);
						while (size > 1)
						{
							size = size / 2;
							levels++;
						}
						return levels;
					}

					public: /*internal*/ int GetPitch(int width)
					{
						//Debug.Assert(width > 0, "The width is negative!");

						int pitch;

						switch (format)
						{
							case SurfaceFormat::Dxt1:
							case SurfaceFormat::RgbPvrtc2Bpp:
							case SurfaceFormat::RgbaPvrtc2Bpp:
							case SurfaceFormat::RgbEtc1:
								//Debug.Assert(MathHelper.IsPowerOfTwo(width), "This format must be power of two!");
								pitch = ((width + 3) / 4) * 8;
								break;

							case SurfaceFormat::Dxt3:
							case SurfaceFormat::Dxt5:
							case SurfaceFormat::RgbPvrtc4Bpp:
							case SurfaceFormat::RgbaPvrtc4Bpp:
								//Debug.Assert(MathHelper.IsPowerOfTwo(width), "This format must be power of two!");
								pitch = ((width + 3) / 4) * 16;
								break;

							case SurfaceFormat::Alpha8:
								pitch = width;
								break;

							case SurfaceFormat::Bgr565:
							case SurfaceFormat::Bgra4444:
							case SurfaceFormat::Bgra5551:
							case SurfaceFormat::NormalizedByte2:
							case SurfaceFormat::HalfSingle:
								pitch = width * 2;
								break;

							case SurfaceFormat::Color:
							case SurfaceFormat::Single:
							case SurfaceFormat::Rg32:
							case SurfaceFormat::HalfVector2:
							case SurfaceFormat::NormalizedByte4:
							case SurfaceFormat::Rgba1010102:
								pitch = width * 4;
								break;

							case SurfaceFormat::HalfVector4:
							case SurfaceFormat::Rgba64:
							case SurfaceFormat::Vector2:
								pitch = width * 8;
								break;

							case SurfaceFormat::Vector4:
								pitch = width * 16;
								break;

							default:
								throw Riccsson::System::NotImplementedException( "Unexpected format!" );
						};

						return pitch;
					}

			#if DIRECTX

					public: /*internal*/ SharpDX.Direct3D11.ShaderResourceView GetShaderResourceView()
					{
						if (_resourceView == null)
							_resourceView = new SharpDX.Direct3D11.ShaderResourceView(GraphicsDevice._d3dDevice, _texture);

						return _resourceView;
					}

			#endif

					public: /*internal*/ protected: override void GraphicsDeviceResetting()
					{
			#if OPENGL
						this.glTexture = -1;
						this.glLastSamplerState = null;
			#endif
					}

					protected: override void Dispose(bool disposing)
					{

						GraphicsResource::Dispose(disposing);
					}
				};
			}
		}
	}
}

#endif
